package com.mybatis.utils;

import com.mybatis.cfg.Mapper;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

/**
 * 查询sql类
 */
public class Executor {

    public <E> List<E> selectList(Mapper mapper, Connection conn){
        PreparedStatement pstm = null;
        ResultSet rs = null;

        try {
            //取出mapper中的数据
            String querySql = mapper.getQuerySql();
            String resultClassName = mapper.getResultClassName();
            Class domainClass = Class.forName(resultClassName);
            //获取PreparedStatement对象
            PreparedStatement preparedStatement = conn.prepareStatement(querySql);
            //执行sql 获取结果
            rs = preparedStatement.executeQuery();
            //封装返回结果集
            List<E> list = new ArrayList<E>();
            while (rs.next()){
                //实例化要封装的实体类对象
                E obj = (E)domainClass.newInstance();
                //取出结果集的元信息
                ResultSetMetaData metaData = rs.getMetaData();
                //取出总列数
                int columnCount = metaData.getColumnCount();
                //遍历总列数
                for (int i = 1; i <= columnCount; i++) {
                    //获取没嘞的名称， 列明的序号是从1开始
                    String columnName = metaData.getColumnName(i);
                    //根据得到列名， 获取每列的值
                    Object columnValue = rs.getObject(columnName);
                    //给ob赋值，使用java内省机制（借助PropertyDescriptor实现属性的封装）
                    PropertyDescriptor pd = new PropertyDescriptor(columnName, domainClass);
                    //获取写入方法
                    Method writeMethod = pd.getWriteMethod();
                    //把获取的列的值，给对象赋值
                    writeMethod.invoke(obj, columnValue);
                }
                //把赋值好的对象加入到集合中
                list.add(obj);

            }
            return list;
        }catch (Exception e){
            throw new RuntimeException(e);
        }finally {
            release(pstm,rs);
        }

    }

    private void release(PreparedStatement pstm, ResultSet rs){
        if(rs != null){
            try {
                rs.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        if(pstm != null){
            try {
                pstm.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}
